/*
 * GeoData.h
 */

#ifndef GEODATA_H_
#define GEODATA_H_

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <vector>
using std::vector;
#include <stdcl.h>

#include "memory.h"
#include "DataPoint.h"

#define SQ(a) ((a)*(a))
#define MIN(a,b) ((a)>(b)?(b):(a))
#define HAVE_OPENCL 1//switch two and from using GPU

///Data class which holds computational variables and methods
class GeoData {

	DataPoint *modelArea;
	int x_size, y_size;
	double deltay, deltax, xscale, yscale;
	int variogram_type, interp_type;
	double range, sill;

	bool Krige(int index);
	bool InvDistWeight(int index);
	vector<int> FindPointsInRange( DataPoint point );
	double GetVariogram(DataPoint one, DataPoint two);
	void QRGivens(double **A, double *B, int n, double *x);
	void QRGivensGPU(double **A, double *B,int n, double *x);

	double SampleGaussianCurve(DataPoint estimate, DataPoint known);
	float gaussRandom();

	double ScaledDistance(DataPoint one, DataPoint two);
	void resetUnknown();

public:
	///Structure to be used in array of unknown points
	struct Unknown {
		int Index;
		long double Sum;
	};

	vector<Unknown> unknown;

	GeoData();
	void SetArea(int x, int y);
	int GetYSize() { return y_size; }
	int GetXSize() { return x_size; }
	void SetDimensions(int x, int y) { deltax = x; deltay = y; }
	double GetDeltaX() { return deltax; }
	double GetDeltaY() { return deltay; }
	void SetScale( double x, double y)
		{ xscale = 1; yscale = deltay/deltax; xscale *= x; yscale *= y; }
	double GetXScale() { return xscale; }
	double GetYScale() { return yscale; }
	void SetUnknownPoint(int x, int y);
	void SetPoint(int x, int y, double value) { modelArea[(x_size*y)+x].setInfo(x, y, value); }
	void SetValue(int index, double value) { modelArea[index].setValue(value); }
	double GetValue(int index) { return modelArea[index].getValue(); }
	double GetValue(int x, int y) { return modelArea[(x_size*y)+x].getValue(); }
	DataPoint GetPoint(int index) { return modelArea[index]; }
	void CalcRange(double &max, double &min);

	void SetVariogram(int type) { variogram_type = type; }
	void SetKnee(double r, double s) { range = r; sill = s; }
	double GetRange() { return range; }
	double GetSill() { return sill; }
	void ExperimentalSemivariogram(double *xsemis, double *ysemis);

	void SetInterpolation(int type) { interp_type = type; }
	vector <Unknown> GetUnknowns() { return unknown; }
	void InterpolatePoints(int ntimes);
	void InterpolateSparsePoints(int ntimes);

	virtual ~GeoData();
};

#endif /* GEODATA_H_ */
